#include <surf.h>

image_info calculate_descriptors(QString filename_string, int surf_threshold){
    CvSeq *keypoints = 0, *descriptors = 0;
    //Некое хранилище
    CvMemStorage* storage = cvCreateMemStorage(0);
    //Далее идет стремная конвертация из QString в массив char
    QByteArray enc = filename_string.toUtf8();
    char* filename = new char[enc.size()+1];
    strcpy(filename,enc.data());

    //Загружаем изображение
    IplImage* object = cvLoadImage(filename, CV_LOAD_IMAGE_GRAYSCALE);

    image_info empty_result;
    if( !object )
    {
        return empty_result;
    }
    //TODO: Обработка ошибок открытия
    //Неведомая фигня
    IplImage* object_color = cvCreateImage(cvGetSize(object), 8, 3);
    cvCvtColor( object, object_color, CV_GRAY2BGR );
    //Настройки SURF
    CvSURFParams parameters = cvSURFParams(surf_threshold, 1);
    //Собственно извлечение дескрипторов
    cvExtractSURF( object, 0, &keypoints, &descriptors, storage, parameters );
    //Вывод общего числа найденых дескрипторов, для проверки
    //printf("Object Descriptors: %d\n", descriptors->total);
    image_info result;
    result.keypoints = keypoints;
    result.descriptors = descriptors;

    //Освобождаем изображения - сильно уменьшаем утечки памяти
    cvReleaseImage(&object);
    cvReleaseImage(&object_color);

    return result;

};

void findPairs(CvSeq *objectDescriptors, CvSeq *imageDescriptors, vector<int>& ptpairs){


    //Не знаю, что это
    int length = (int)(objectDescriptors->elem_size/sizeof(float));

    //Матрицы для хранения данных
    cv::Mat m_object(objectDescriptors->total, length, CV_32F);
    cv::Mat m_image(imageDescriptors->total, length, CV_32F);

    //Копирование дескрипторов 1
    CvSeqReader obj_reader;
    float* obj_ptr = m_object.ptr<float>(0);
    cvStartReadSeq( objectDescriptors, &obj_reader );
    for(int i = 0; i < objectDescriptors->total; i++ )
    {
        const float* descriptor = (const float*)obj_reader.ptr;
        CV_NEXT_SEQ_ELEM( obj_reader.seq->elem_size, obj_reader );
        memcpy(obj_ptr, descriptor, length*sizeof(float));
        obj_ptr += length;
    }

    //Копирование дескрипторов 2
    CvSeqReader img_reader;
    float* img_ptr = m_image.ptr<float>(0);
    cvStartReadSeq( imageDescriptors, &img_reader );
    for(int i = 0; i < imageDescriptors->total; i++ )
    {
        const float* descriptor = (const float*)img_reader.ptr;
        CV_NEXT_SEQ_ELEM( img_reader.seq->elem_size, img_reader );
        memcpy(img_ptr, descriptor, length*sizeof(float));
        img_ptr += length;
    }

    //Собственно, сравнение дескрипторов
    cv::Mat m_indices(objectDescriptors->total, 2, CV_32S);
    cv::Mat m_dists(objectDescriptors->total, 2, CV_32F);
    cv::flann::Index flann_index(m_image, cv::flann::KDTreeIndexParams(4));  // using 4 randomized kdtrees
    flann_index.knnSearch(m_object, m_indices, m_dists, 2, cv::flann::SearchParams(64) ); // maximum number of leafs checked

    int* indices_ptr = m_indices.ptr<int>(0);
    float* dists_ptr = m_dists.ptr<float>(0);
    for (int i=0;i<m_indices.rows;++i) {
        if (dists_ptr[2*i]<0.6*dists_ptr[2*i+1]) {
                ptpairs.push_back(i);
                ptpairs.push_back(indices_ptr[2*i]);
        }
    }
};

char* strToChar(QString str){
    QByteArray enc = str.toUtf8();
    char* filename = new char[enc.size()+1];
    strcpy(filename,enc.data());
    return filename;

}




int search(QString filename_string, QString directory_string){

    CvSeq *objectKeypoints = 0, *objectDescriptors = 0;
    CvMemStorage* storage = cvCreateMemStorage(0);
    char* filename = strToChar(filename_string);

    //Загружаем изображение
    IplImage* object = cvLoadImage(filename, CV_LOAD_IMAGE_GRAYSCALE);
    //Проверяем, загрузилось ли изображение для поиска
    if( !object )
    {
        qDebug()<<"LOLFAIL, failed to load image "<< filename_string;
        return 1;
    }

    //Изображение преобразуется в черно-белое
    IplImage* object_color = cvCreateImage(cvGetSize(object), 8, 3);
    cvCvtColor( object, object_color, CV_GRAY2BGR );
    //Настройки SURF
    int surf_threshold = 1000;
    CvSURFParams parameters = cvSURFParams(surf_threshold, 1);
    //Собственно извлечение дескрипторов
    cvExtractSURF( object, 0, &objectKeypoints, &objectDescriptors, storage, parameters );

    int i = 0;

    //Извлекаем список файлов из каталога
    QDir dir(directory_string);
    QStringList filters;
    filters << "*.jpg" << "*.png";
    QStringList list = dir.entryList(filters, QDir::Files);
    //Проверяем, что в каталоге есть изображения
    if (list.size() == 0)
    {
        qDebug()<<"LOLFAIL, there are no images in the folder";
        return 1;
    }

    //Сравниваем каждое изображение в каталоге с искомым
    for (i = 0; i<list.size(); i++){
        CvSeq *sceneKeypoints = 0, *sceneDescriptors = 0;
        //Меняем имя файла в диалоге
        QString buf = list.at(i);
        //emit change(buf);
        //Меняем проценты в прогрессбаре диалога
        //emit bump(i);


        //Грузим изображение для сравнения
        IplImage* scene = cvLoadImage(strToChar(dir.absolutePath()+QDir::separator()+list.at(i)), CV_LOAD_IMAGE_GRAYSCALE);
        //Проверяем, загрузилось ли
        if( !scene )
        {
            qDebug()<<"LOLFAIL, failed to load image "<< filename_string;
            continue;
        }
        //Извлекаем из него дескрипторы
        cvExtractSURF( scene, 0, &sceneKeypoints, &sceneDescriptors, storage, parameters );

        //Ищем пары
        vector<int> ptpairs;
        findPairs(objectDescriptors, sceneDescriptors, ptpairs);
        qDebug()<<"RESULT: In image " << buf << " were found " << ptpairs.size()<<" pairs";

    }

    return 0;


}









